package cn.iocoder.yudao.module.signature.service.signinfo;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.text.CharSequenceUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.ipa.IconReplacer;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.shortchain.ShortChainUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.member.api.siteconfig.SiteConfigurationApi;
import cn.iocoder.yudao.module.member.api.siteconfig.dto.SiteConfigurationDto;
import cn.iocoder.yudao.module.signature.controller.app.signinfo.vo.ApplicationSignInfoPageReqVO;
import cn.iocoder.yudao.module.signature.controller.app.signinfo.vo.ApplicationSignInfoSaveReqVO;
import cn.iocoder.yudao.module.signature.dal.dataobject.application.ApplicationInfoDO;
import cn.iocoder.yudao.module.signature.dal.dataobject.device.AppleDeviceDO;
import cn.iocoder.yudao.module.signature.dal.dataobject.signinfo.ApplicationSignInfoDO;
import cn.iocoder.yudao.module.signature.dal.mysql.signinfo.ApplicationSignInfoMapper;
import cn.iocoder.yudao.module.signature.enums.ApplicationSignStatus;
import cn.iocoder.yudao.module.signature.service.application.ApplicationInfoService;
import cn.iocoder.yudao.module.signature.service.device.AppleDeviceService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.signature.enums.ErrorCodeConstants.APPLICATION_SIGN_INFO_NOT_EXISTS;

/**
 * 应用签名记录 Service 实现类
 *
 * @author base
 */
@Service
@Validated
@Slf4j
public class ApplicationSignInfoServiceImpl implements ApplicationSignInfoService {

    @Value("${yudao.domain}")
    private String domain;

    @Resource
    private ApplicationSignInfoMapper applicationSignInfoMapper;

    @Resource
    private FileApi fileApi;


    @Resource
    private AppleDeviceService deviceService;

    @Resource
    private ApplicationInfoService applicationInfoService;

    @Value("${yudao.signature.max-sign-count:5}")
    private Integer maxSignCount;

    @Resource
    private RedisTemplate<String, Integer> redisTemplate;

    @Resource
    @Lazy
    private ApplicationSignInfoService applicationSignInfoService;

    @Resource
    private SiteConfigurationApi siteConfigurationApi;

    @Resource(name = "signTaskExecutor")
    private ThreadPoolTaskExecutor signTaskExecutor;

    /**
     * 签名任务数量
     */
    private static final String SIGN_TASK_NUM = "sign_task_num";


    @Transactional(rollbackFor = Exception.class )
    @Override
    public Long createApplicationSignInfo(ApplicationSignInfoSaveReqVO createReqVO) throws Exception {


        LoginUser user = SecurityFrameworkUtils.getLoginUser();
        Assert.notNull(user, "用户不能为空");

        AppleDeviceDO deviceDO = deviceService.getAppleDevice(createReqVO.getDeviceId());
        Assert.notNull(deviceDO, "设备不存在证书");
        Assert.isTrue(Objects.equals(deviceDO.getUserId(), user.getId()), "设备不属于当前用户");

        Assert.isTrue(StringUtils.isNotBlank(deviceDO.getMpUrl()), "苹果官方审核中");

        int addNum = createReqVO.getAddNum() == null ? 1 : createReqVO.getAddNum();
        int paNum = createReqVO.getFromNum() == null ? 1 : createReqVO.getFromNum();
        Integer fromNum = createReqVO.getFromNum();
        List<ApplicationSignInfoDO> applicationSignInfoList = new ArrayList<>();
        for(int i = 0; i < addNum; i++){
            // 插入
            ApplicationSignInfoDO applicationSignInfo = BeanUtils.toBean(createReqVO, ApplicationSignInfoDO.class);
            applicationSignInfo.setId(null);
            applicationSignInfo.setCerNumber(deviceDO.getCerNumber());
            applicationSignInfo.setStatus(ApplicationSignStatus.QUEUE.getType());
            if(addNum > 1){
                if(createReqVO.getFromNum() == null || createReqVO.getFromNum() == 0){
                    applicationSignInfo.setPacketName(applicationSignInfo.getPacketName() + (i+1));
                }else{
                    applicationSignInfo.setPacketName(applicationSignInfo.getPacketName() + fromNum);
                    fromNum++;
                }
                if(paNum > 0){
                    applicationSignInfo.setApplicationName(applicationSignInfo.getApplicationName() + paNum);
                    paNum++;
                }
            }
            String signIpa = UUID.fastUUID() + ".ipa";
            String signIpaUrl = fileApi.createFile(signIpa, "signIpa", new byte[0]);
            applicationSignInfo.setApplicationUrl(signIpaUrl);
            //应用url
            ApplicationInfoDO applicationInfo = applicationInfoService.getApplicationInfo(applicationSignInfo.getApplicationId());
            Assert.notNull(applicationInfo, "应用不存在");
            String installUrl = ShortChainUtil.getInstallUrl(applicationSignInfo.getApplicationName(), applicationSignInfo.getIconImg(), applicationSignInfo.getPacketName(), signIpaUrl,siteConfigurationApi.getConfig().getDomainName());
            applicationSignInfo.setInstallUrl(installUrl);

            applicationSignInfoMapper.insert(applicationSignInfo);
            if(StringUtils.isNotBlank(applicationInfo.getIconImg())){
                fileApi.moveFile(CharSequenceUtil.subAfter(applicationInfo.getIconImg(), "/get/", false),"icon");
            }
            applicationSignInfoList.add(applicationSignInfo);
        }

        this.sumitSignTask(applicationSignInfoList);
        // 返回
        return applicationSignInfoList.get(0).getId();
    }

    private void sumitSignTask(List<ApplicationSignInfoDO> applicationSignInfoDOs) {
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCompletion(int status) {
                if (status == TransactionSynchronization.STATUS_COMMITTED) {
                    log.info("提交签名任务:{}",applicationSignInfoDOs.get(0).getId()  );

                    signTaskExecutor.submit(() -> {
                        try {
                            applicationSignInfoDOs.forEach(applicationSignInfoDO -> {
                                log.info("开始签名任务:{}", applicationSignInfoDO.getId());
                                doSign(applicationSignInfoDO, deviceService.getAppleDevice(applicationSignInfoDO.getDeviceId()));
                            });
                        } catch (Exception e) {
                            log.error("签名失败", e);
                        }
                    });
                }
            }
        });

    }

    @Override
    public Integer checkSignComplete(String url) throws Exception {
        log.info("checkSignComplete=={}",url);
        ApplicationSignInfoDO applicationSignInfoDO = applicationSignInfoMapper.selectOne(ApplicationSignInfoDO::getInstallUrl, url);

        if (applicationSignInfoDO != null) {
            if (Objects.equals(applicationSignInfoDO.getStatus(), ApplicationSignStatus.PACKAGED.getType())) {
               if(!fileApi.exists(CharSequenceUtil.subAfter(applicationSignInfoDO.getApplicationUrl(), "/get/", false))){
                   return 2;
               }
                return 1;
            } else   {
                return 0;
            }
        }else {
            return 2;
        }
    }


    private void checkSignTaskNum() {

        SiteConfigurationDto config = siteConfigurationApi.getConfig();

        Integer num = redisTemplate.opsForValue().get(SIGN_TASK_NUM);
        if (num == null) {
            redisTemplate.opsForValue().set(SIGN_TASK_NUM, 0);
            Assert.isTrue(null != config && config.getNumberLimit() > 0, "签名任务已满,请稍后再试");
        }
        if (num == null || config.getNumberLimit() == null) {
            Assert.isTrue(false, "签名任务已满,请稍后再试");
        }
        if (num >= config.getNumberLimit()) {
            log.info("签名任务已满 已签{},总数 {}", num, config.getNumberLimit());
            Assert.isTrue(false, "签名任务已满,请稍后再试");
        }
    }

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public ApplicationSignInfoDO signCard(ApplicationSignInfoSaveReqVO createReqVO) throws Exception {
        int activeCount = signTaskExecutor.getActiveCount();
        Integer numberLimit = siteConfigurationApi.getConfig().getNumberLimit();
        if (activeCount >= numberLimit) {
            log.info("签名任务已满 已签{},总数 {}", activeCount, numberLimit);
            Assert.isTrue(false, "签名任务已满,请稍后再试");
        }


        AppleDeviceDO deviceDO = deviceService.getAppleDevice(createReqVO.getDeviceId());
        Assert.notNull(deviceDO, "该设备不存在证书，请先购买证书");

        Assert.isTrue(StringUtils.isNotBlank(deviceDO.getMpUrl()), "苹果官方审核中");

        ApplicationSignInfoDO applicationSignInfo = BeanUtils.toBean(createReqVO, ApplicationSignInfoDO.class);
        applicationSignInfo.setId(null);
        applicationSignInfo.setUserId(1000000L);
        applicationSignInfo.setCerNumber(deviceDO.getCerNumber());
        applicationSignInfo.setStatus(ApplicationSignStatus.QUEUE.getType());
        String signIpa = UUID.fastUUID() + ".ipa";
        String signIpaUrl = fileApi.createFile(signIpa, "signIpa", new byte[0]);
        applicationSignInfo.setApplicationUrl(signIpaUrl);
        ApplicationInfoDO applicationInfo = applicationInfoService.getApplicationInfo(applicationSignInfo.getApplicationId());
        Assert.notNull(applicationInfo, "应用不存在");
        log.info("签名信息:{}", JSON.toJSONString(applicationSignInfo));
        String installUrl = ShortChainUtil.getInstallUrl(applicationSignInfo.getApplicationName(), applicationSignInfo.getIconImg(), applicationSignInfo.getPacketName(), signIpaUrl, siteConfigurationApi.getConfig().getDomainName());
        applicationSignInfo.setInstallUrl(installUrl);
        applicationSignInfoService.insertApplicationSignInfoNow(applicationSignInfo);
        // 签名
        this.doSign(applicationSignInfo, deviceDO);

        if(StringUtils.isNotBlank(applicationInfo.getIconImg())){
            fileApi.moveFile(CharSequenceUtil.subAfter(applicationInfo.getIconImg(), "/get/", false),"icon");
        }

        return applicationSignInfo;
    }

    @Override
    public void updateApplicationSignInfo(ApplicationSignInfoSaveReqVO updateReqVO) {
        // 校验存在
        validateApplicationSignInfoExists(updateReqVO.getId(), updateReqVO.getUserId());
        // 更新
        ApplicationSignInfoDO updateObj = BeanUtils.toBean(updateReqVO, ApplicationSignInfoDO.class);
        applicationSignInfoMapper.updateById(updateObj);
    }

    @Override
    public void deleteApplicationSignInfo(List<Long> ids, Long userId) {
        // 删除
        applicationSignInfoMapper.deleteByIds(ids);
    }

    private void validateApplicationSignInfoExists(Long id, Long userId) {
        if (applicationSignInfoMapper.selectOne(new LambdaQueryWrapperX<ApplicationSignInfoDO>().eq(ApplicationSignInfoDO::getId, id).eq(ApplicationSignInfoDO::getUserId, userId)) == null) {
            throw exception(APPLICATION_SIGN_INFO_NOT_EXISTS);
        }
    }

    @Override
    public ApplicationSignInfoDO getApplicationSignInfo(Long id) {
        return applicationSignInfoMapper.selectById(id);
    }

    @Override
    public PageResult<ApplicationSignInfoDO> getApplicationSignInfoPage(ApplicationSignInfoPageReqVO pageReqVO) {
        return applicationSignInfoMapper.selectPage(pageReqVO);
    }

    @Override
    public void excuteSignTask() throws Exception {
//        SiteConfigurationDto config = siteConfigurationApi.getConfig();
//        int threadCount = config.getNumberLimit();
//
//        // 用于追踪正在执行任务的线程数
//        AtomicInteger activeThreadCount = new AtomicInteger(0);
//
//        // 创建固定大小的线程池
//        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
//
//
//        for (int i = 0; i < threadCount; i++) {
//            int finalI = i;
//            executorService.submit(() -> {
//                while (true) {
//
//                    try {
//                        Thread.sleep(finalI * 50);
//                    } catch (InterruptedException e) {
//                        throw new RuntimeException(e);
//                    }
//                    List<ApplicationSignInfoDO> applicationSignInfoDOS = applicationSignInfoMapper.selectQueue(1);
//
//                    if (CollectionUtils.isEmpty(applicationSignInfoDOS) && activeThreadCount.get() == 0) {
//                        break;
//                    }
//                    if (CollectionUtils.isEmpty(applicationSignInfoDOS)) {
//                        continue;
//                    }
//
//                    ApplicationSignInfoDO task = applicationSignInfoDOS.get(0);
//
//                    if (task.getDeviceId() == null) {
//                        continue;
//                    }
//
//                    AppleDeviceDO deviceDO = deviceService.getAppleDevice(task.getDeviceId());
//                    if (deviceDO == null) {
//                        task.setStatus(ApplicationSignStatus.PACKAGE_FAILED.getType());
//                        applicationSignInfoService.upApplicationSignInfoNow(task);
//                        continue;
//                    }
//                    task.setStatus(ApplicationSignStatus.PACKAGING.getType());
//                    applicationSignInfoService.upApplicationSignInfoNow(task);
//                    activeThreadCount.incrementAndGet();
//
//                    try {
//                        Thread.sleep(finalI * 50);
//                        doSign(task, deviceDO);
//                    }catch (Exception e){
//                        log.error("签名失败", e);
//                    }
//                    activeThreadCount.decrementAndGet();
//
//                }
//
//            });
//
//        }
//
//        Thread.sleep(1000);
//        while (true) {
//            if (activeThreadCount.get() == 0) {
//                // 关闭线程池
//                executorService.shutdown();
//                break;
//            } else {
//                Thread.sleep(100);
//            }
//        }

    }

    @Override
    public void excuteSignTaskTest(Long id) throws Exception {
        ApplicationSignInfoDO applicationSignInfoDO = applicationSignInfoMapper.selectById(id);
        if (applicationSignInfoDO == null) {
            return;
        }
//        doSign(applicationSignInfoDO);
    }

    /**
     * 获取锁定时间检查URL
     *
     * @param signInfoDO
     * @return
     */
    private String getLockTimeCheckUrl(ApplicationSignInfoDO signInfoDO) {
        return domain + "/app-api/signature/application-sign-info/lockTimeCheck?id=" + signInfoDO.getId();
    }

    @Override
    public String testPackaging(MultipartFile file) throws Exception {

        File ipaFile = File.createTempFile(FileUtil.getPrefix(file.getName()), FileUtil.getSuffix(".p12"));
        file.transferTo(ipaFile);

        String signIpa = UUID.fastUUID() + ".ipa";
         String signIpaUrl = fileApi.createFile(signIpa, "signIpa", new byte[0]);

        String signIpaPath = CharSequenceUtil.subAfter(signIpaUrl, "/get/", false);
        String signIpaConfig = signIpaUrl.substring(signIpaUrl.indexOf("/file/") + "/file/".length(), signIpaUrl.indexOf("/get/"));
        String signIpaFilePath = fileApi.getFilePath(Long.valueOf(signIpaConfig), signIpaPath);


        // zsign -k 证书.p12 -p 证书密码 -m 描述文件.mobileprovision -o 签名后的ipa文件.ipa 待签名的ipa文件.ipa
        String signCommand = "/work/tool/zsign -k " + "/work/file/bbd2ee63-68fd-4731-b1a4-da0cf537cd0f.p12"
                + " -p 1"  + " -m " + "/work/file/6b8feaf6-fbaa-49a4-9219-b1a6c8515800.mobileprovision" + " -o " + signIpaFilePath + " -b " + "test"
                + " -n " + "test" + " -z 1 " + ipaFile;
        log.info("执行命令:{}", signCommand);

        // 使用zsign进行签名
        Process process = Runtime.getRuntime().exec(signCommand);
        // 获取命令输出
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            log.info(line);
        }
        // 等待命令执行完成
        int exitCode = process.waitFor();
        log.info("Command executed with exit code: " + exitCode);
        if (exitCode != 0) {
            throw new RuntimeException("签名失败");
        }


        String installUrl = ShortChainUtil.getInstallUrl("test", "https://mmc.888xh.cn/admin-api/infra/file/24/get/98eb162b-5bbe-469a-86fe-dc312a3dec09.png", "com.test", signIpaUrl,"");
        log.info("installUrl:{}", installUrl);
        return installUrl;
    }

    @Override
    public List<ApplicationSignInfoDO> listRecentData(Long userId) {
        return  applicationSignInfoMapper.listRecentData(userId);
    }


    @Override
    public void doSign(ApplicationSignInfoDO signInfoDO, AppleDeviceDO deviceDO) {

//        this.checkSignTaskNum();

        signInfoDO.setStatus(ApplicationSignStatus.PACKAGING.getType());
        applicationSignInfoService.upApplicationSignInfoNow(signInfoDO);
//        applicationSignInfoMapper.updateById(signInfoDO);

        log.info("开始签名任务:{}", JSON.toJSONString(signInfoDO));
//        redisTemplate.opsForValue().increment(SIGN_TASK_NUM, 1);
        try {
            signInfoDO.setStatus(ApplicationSignStatus.PACKAGED.getType());
            // todo ljq udid获取唯一性问题
            Assert.notNull(deviceDO, "设备不存在证书");
            Assert.isTrue(StringUtils.isNotBlank(deviceDO.getMpUrl()), "苹果官方审核中");
            log.info("判断证书");

            //描述文件url
            String mpUrl = deviceDO.getMpUrl();
            String mpPath = CharSequenceUtil.subAfter(mpUrl, "/get/", false);
            String mpConfigId = mpUrl.substring(mpUrl.indexOf("/file/") + "/file/".length(), mpUrl.indexOf("/get/"));
            String mpFilePath = fileApi.getFilePath(Long.valueOf(mpConfigId), mpPath);
            log.info("mpFilePath:{}", mpFilePath);

            //p12文件url
            String p12Url = deviceDO.getP12Url();
            String p12Path = CharSequenceUtil.subAfter(p12Url, "/get/", false);
            String p12Config = p12Url.substring(p12Url.indexOf("/file/") + "/file/".length(), p12Url.indexOf("/get/"));
            String p12FilePath = fileApi.getFilePath(Long.valueOf(p12Config), p12Path);
            log.info("p12FilePath:{}", p12FilePath);

            //应用url
            ApplicationInfoDO applicationInfo = applicationInfoService.getApplicationInfo(signInfoDO.getApplicationId());
            Assert.notNull(applicationInfo, "应用不存在");
            String appUrl = applicationInfo.getApplicationUrl();
            String appPath = CharSequenceUtil.subAfter(appUrl, "/get/", false);
            String appConfig = appUrl.substring(appUrl.indexOf("/file/") + "/file/".length(), appUrl.indexOf("/get/"));
            String appFilePath = fileApi.getFilePath(Long.valueOf(appConfig), appPath);
            log.info("appFilePath:{}", appFilePath);

            String iconPath = CharSequenceUtil.subAfter(signInfoDO.getIconImg(), "/get/", false);
            String iconConfig = applicationInfo.getIconImg().substring(applicationInfo.getIconImg().indexOf("/file/") + "/file/".length(), applicationInfo.getIconImg().indexOf("/get/"));
            String iconFilePath = fileApi.getFilePath(Long.valueOf(iconConfig), iconPath);

            // 复制一个应用文件
            File tempFile = FileUtil.createTempFile("hutool", "." + FileUtil.getSuffix(new File(appFilePath)), new File("/home/file/up_tmp"),true);
            log.info("tempFile:{}", tempFile.getAbsolutePath());
            FileUtil.copy(new File(appFilePath), tempFile, true);

            log.info("开始签名");

            String dylib = "";
            IconReplacer iconReplacer = new IconReplacer(tempFile.getAbsolutePath(), iconFilePath);
            if (null != signInfoDO.getTimeLockDays()) {
                iconReplacer.replaceIconAddDyLib(this.getLockTimeCheckUrl(signInfoDO));
                dylib = " -l /work/tool/zsign.dylib";
            } else {
                iconReplacer.replaceIcon();
            }

            // 创建一个签名后ipa文件
            String signIpaUrl = signInfoDO.getApplicationUrl();
            if (StringUtils.isBlank(signIpaUrl)) {
                String signIpa = UUID.fastUUID() + ".ipa";
                signIpaUrl = fileApi.createFile(signIpa, "signIpa", new byte[0]);
            }
            String signIpaPath = CharSequenceUtil.subAfter(signIpaUrl, "/get/", false);
            String signIpaConfig = signIpaUrl.substring(signIpaUrl.indexOf("/file/") + "/file/".length(), signIpaUrl.indexOf("/get/"));
            String signIpaFilePath = fileApi.getFilePath(Long.valueOf(signIpaConfig), signIpaPath);

            // zsign -k 证书.p12 -p 证书密码 -m 描述文件.mobileprovision -o 签名后的ipa文件.ipa 待签名的ipa文件.ipa
            String signCommand = "/work/tool/zsign -k " + p12FilePath + dylib
                    + " -p " + deviceDO.getP12Password() + " -m " + mpFilePath + " -o " + signIpaFilePath + " -b " + signInfoDO.getPacketName()
                    + " -n " + signInfoDO.getApplicationName() + " -z 1 " + tempFile.getAbsolutePath();
            log.info("执行命令:{}", signCommand);

            // 使用zsign进行签名
            Process process = Runtime.getRuntime().exec(signCommand);
            // 获取命令输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                log.info(line);
            }
            // 等待命令执行完成
            int exitCode = process.waitFor();
            log.info("Command executed with exit code: " + exitCode);
            if (exitCode != 0) {
                throw new RuntimeException("签名失败");
            }
            tempFile.delete();
//            log.info("临时文件删除:{}", tempFile.getAbsolutePath());

            //生成plist文件
            String plist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                    "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" +
                    "<plist version=\"1.0\">\n" +
                    "<dict>\n" +
                    "    <key>items</key>\n" +
                    "    <array>\n" +
                    "        <dict>\n" +
                    "            <key>assets</key>\n" +
                    "            <array>\n" +
                    "                <dict>\n" +
                    "                    <key>kind</key>\n" +
                    "                    <string>software-package</string>\n" +
                    "                    <key>url</key>\n" +
                    "                    <string>" + signIpaUrl + "</string>\n" +
                    "                </dict>\n" +
                    "            </array>\n" +
                    "            <key>metadata</key>\n" +
                    "            <dict>\n" +
                    "                <key>bundle-identifier</key>\n" +
                    "                <string>" + signInfoDO.getPacketName() + "</string>\n" +
                    "                <key>bundle-version</key>\n" +
                    "                <string>" + applicationInfo.getApplicationVersion() + "</string>\n" +
                    "                <key>kind</key>\n" +
                    "                <string>software</string>\n" +
                    "                <key>title</key>\n" +
                    "                <string>" + signInfoDO.getApplicationName() + "</string>\n" +
                    "            </dict>\n" +
                    "        </dict>\n" +
                    "    </array>\n" +
                    "</dict>\n" +
                    "</plist>";

            signInfoDO.setApplicationUrl(signIpaUrl);
            String plistFileUrl = fileApi.createFile(signInfoDO.getApplicationName(), "plist", plist.getBytes());
            signInfoDO.setPlistUrl(plistFileUrl);
            signInfoDO.setApplicationVersion(applicationInfo.getApplicationVersion());
            signInfoDO.setApplicationSize(applicationInfo.getApplicationSize());

        } catch (Exception e) {
            log.error("签名失败", e);
            signInfoDO.setStatus(ApplicationSignStatus.PACKAGE_FAILED.getType());
        } finally {
//            redisTemplate.opsForValue().decrement(SIGN_TASK_NUM, 1);
        }
        log.info("签名任务完成:{}", JSON.toJSONString(signInfoDO));
        applicationSignInfoMapper.updateById(signInfoDO);


    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public void upApplicationSignInfoNow(ApplicationSignInfoDO signInfoDO) {
        applicationSignInfoMapper.updateById(signInfoDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void insertApplicationSignInfoNow(ApplicationSignInfoDO signInfoDO) {
        applicationSignInfoMapper.insert(signInfoDO);
    }

    @Override
    public CommonResult lockTimeCheck(Long id) {
        log.info("时间锁检查:{}", id);
        ApplicationSignInfoDO applicationSignInfoDO = applicationSignInfoMapper.selectById(id);
        CommonResult commonResult = new CommonResult();
        if (null == applicationSignInfoDO) {
            log.warn("签名任务不存在");
            commonResult.setCode(0);
            commonResult.setMsg("设备已禁用");
            return commonResult;
        }

        if (Objects.equals(applicationSignInfoDO.getTimeLockFlag(), 1)) {
            commonResult.setCode(0);
            commonResult.setMsg("此设备已到期！请联系客服续期");
            return commonResult;
        }

        if (applicationSignInfoDO.getTimeLockDays() == null) {
            log.warn("此签名任务没有时间锁");
            commonResult.setCode(0);
            commonResult.setMsg("设备已禁用");
            return commonResult;
        }

        // 计算是否过期
        long time = Timestamp.valueOf(applicationSignInfoDO.getCreateTime()).getTime() + (applicationSignInfoDO.getTimeLockDays() * 24 * 60 * 60 * 1000L);
        if (System.currentTimeMillis() > time) {
            log.warn("时间锁检查未通过");
            commonResult.setCode(0);
            commonResult.setMsg("此设备已到期！请联系客服续期");
            return commonResult;
        }

        commonResult.setCode(1);
        commonResult.setMsg("请求成功");
        return commonResult;
    }

}